/*
 * Copyright 2007-2009 Thomas Krause (thomas@berlin-reloaded.de)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.gidoo.wickettools;

/**
 * This class produces a visual diff using XHTML as output.
 * It uses it's own very simple diff-algorithm which will always show the
 * correct old and new versions but may be "wrong" in the decision wether 
 * a line was changed, deleted or inserted in certain situations.
 * @author <a href="mailto:thomas@berlin-reloaded.de">Thomas Krause</a>
 */
public class XHTMLDiff
{

  /**
   * Creates a new instance of XHTMLDiff
   */
  public XHTMLDiff()
  {
  }
  
  /**
   * Compares s1 (older) and s2 (newer).
   *
   * @param s1
   * @param s2
   * @param captionOld
   * @param captionNew
   * @return XHTML-Code (without head, body and especially without table and th)
   */
  public static String doDiff(String s1, String s2, String captionOld, String captionNew)
  {
    if(s1 == null || s2 == null)
      return "";
    
    // mask special XHTML characters
    s1 = maskXHTML(s1);
    s2 = maskXHTML(s2);
    
    String[] split1 = s1.split("(\\r\\n)|(\\n)|(\\r)");
    String[] split2 = s2.split("(\\r\\n)|(\\n)|(\\r)");
            
    int i=0;
    int j=0;

    captionOld = captionOld == null ? "" : captionOld;
    captionNew = captionNew == null ? "" : captionNew;

    String result =
      "<style type=\"text/css\">\n" +
      ".diffTable {\n" +
      "text-align:left;width:100%;border-style:none;border-collapse:collapse;\n" +
      "}\n" +
      ".diffTable td {\n" +
      "border-style:dotted;border-color:gray;border-width:1px;\n" +
      "}\n" +
      "</style>\n" +
      "<table class=\"diffTable\">" +
      "<tr style=\"text-align:center\">" +
      "<th>" + captionOld + "</th><th>" + captionNew + "</th>\n";
    
    while(i < split1.length || j < split2.length)
    {
      
      if(i < split1.length && j < split2.length && split1[i].equals(split2[j]))
      {
        result += "<tr><td>" + split1[i] + "</td><td>" + split2[j] + "</td></tr>";
        
        i++;
        j++;
      }
      else
      {
        // test for insert
        boolean wasInserted = false;
        int j_ins = j + 1;

        if(j >= split1.length && j == (split2.length-1))
        {
          // one line inserted at the end
          wasInserted = true;
          j_ins = split2.length;
        }
        else
        {
          
          while(j_ins < split2.length)
          {
            if(i >= split1.length || split1[i].equals(split2[j_ins]))
            {
              wasInserted = true;
              break;
            }
            j_ins++;
          }
        }
        
        if(wasInserted)
        {
          while(j < j_ins)
          {
            result += "<tr><td></td><td style=\"color:green\">" + split2[j] +
              "</td></tr>\n";
            
            j++;
          }
        }
        else
        {
          // test for delete
          boolean wasDeleted = false;
          int i_del = i + 1;
          if(i >= split2.length && i == (split1.length-1))
          {
            // one line at the end was deleted
            wasDeleted = true;
            i_del = split1.length;
          }
          else
          {
            while(i_del < split1.length)
            {
              if(j >= split2.length || split1[i_del].equals(split2[j]))
              {
                wasDeleted = true;
                break;
              }
              i_del++;
            }
          }
          if(wasDeleted)
          {
            while(i < i_del)
            {
              result += "<tr><td style=\"color:red;text-decoration:line-through;\">" +
                split1[i] + "</td><td></td></tr>\n";
              
              i++;
            } 
          }
          else
          {
            // must have been a change
            String l = "";
            if(i < split1.length)
            {
              l = split1[i];
            }
            String r = "";
            if(j < split2.length)
            {
              r = split2[j];
            }
            
            result += "<tr><td style=\"color:orange;\">" + l +
              "</td><td style=\"color:orange;\">" + r + "</td></tr>\n";
            
            i++;
            j++;
          }
        }
        
      }
      
    }
    
    result += "</table>\n";

    return result;
  }
  
  public static String maskXHTML(String s)
  {
    String result = "" + s;
    result = result.replaceAll("<", "&lt;");
    result = result.replaceAll(">", "&gt;");
    
    return result;
  }
}
